package main

import (
	"fmt"
	"database/sql"
	"sync/atomic"
	"strings"
	 _ "github.com/go-sql-driver/mysql"

)

/* TO DO : i don't know why 10 , should use anther better number like CPU number*2 */

const (
	PUSH_MSG = "INSERT INTO message(type,`from`,`to`,data,time,ext) VALUES(?,?,?,?,?,?)"
	GET_MSGS = "SELECT id,type,`from`,`to`,data,time,ext FROM message WHERE ((FIND_IN_SET(?,`to`) AND `from`=?) OR (FIND_IN_SET(?,`from`) AND `to`=?)) AND id>? ORDER BY time"
	GET_MSGS_BY_TYPE = "SELECT id,type,`from`,`to`,data,time,ext FROM message WHERE FIND_IN_SET(?,`to`) AND type=? AND id>? ORDER BY time"
)

type DB interface {
	PushMsg(msg *Msg) error
	GetMsgs(key string,id int) ([]*Msg,error)
	GetMsgsFromType(key string,id int,ty string) ([]*Msg,error)
	DeleteMsgs(id int) error
}

var CountDb int64 = 0

type MysqlDB struct {
	pool []*sql.DB
	size int
}

func InitMysqlDB() *MysqlDB {
	mysqlDB := &MysqlDB{pool:[]*sql.DB{}}
	fmt.Println("db connecting")
	for i := 0;i < 10;i++{
		db, err := sql.Open("mysql", "root:123456@/yipush")
		if err != nil{
			fmt.Println("db connect Error :",i,err)
		}else{
			fmt.Println("db connect Success",i,db)
			mysqlDB.pool = append(mysqlDB.pool,db)
		}
	}
	mysqlDB.size = len(mysqlDB.pool)
	return mysqlDB
}

func (md *MysqlDB)getDB() *sql.DB{
	atomic.AddInt64(&CountDb,1)
	return 	md.pool[CountDb%int64(md.size)]
}

func (md *MysqlDB)PushMsg(msg *Msg) error{
	db := md.getDB()
	fmt.Println("db:",db)
	_,err := db.Exec(PUSH_MSG,msg.Ty,msg.From,strings.Join(msg.To,","),msg.Data,msg.Time,msg.Ext)
	if err != nil{
		fmt.Println("PushMsg() fail :",err)
		return err
	}
	rows,_ := db.Query("SELECT LAST_INSERT_ID()")
	rows.Next()
	rows.Columns()
	var id int
	rows.Scan(&id)
	msg.Id = id
	fmt.Println(" PushMsg() success id:",id,err)
	return nil
}

func (md *MysqlDB)GetMsgs(me string,key string,minId int) ([]*Msg,error){
	rows,err := md.getDB().Query(GET_MSGS,me,key,me,key,minId)
	if err != nil{
		fmt.Println("GetMsgs fail :",err)
		return nil,err
	}
	msgs := []*Msg{}
	for rows.Next(){
		var id int
		var ty string
		var from string
		var to string
		var data string
		var time int64
		var ext string
		rows.Columns()
		rows.Scan(&id,&ty,&from,&to,&data,&time,&ext)
		msgs = append(msgs,&Msg{id,ty,from,strings.Split(to,","),data,time,ext})
	}
	return msgs,nil
}

func (md *MysqlDB)GetMsgsFromType(key string,minId int,ty string) ([]*Msg,error){
	rows,err := md.getDB().Query(GET_MSGS_BY_TYPE,key,ty,minId)
	if err != nil{
		fmt.Println("GetMsgsFromType fail :",err)
		return nil,err
	}
	msgs := []*Msg{}
	for rows.Next(){
		var id int
		var ty string
		var from string
		var to string
		var data string
		var time int64
		var ext string
		rows.Columns()
		rows.Scan(&id,&ty,&from,&to,&data,&time,&ext)
		msgs = append(msgs,&Msg{id,ty,from,strings.Split(to,","),data,time,ext})
	}
	return msgs,nil
}
func (md *MysqlDB)DeleteMsgs(id int) error {
	if _, err := md.getDB().Exec("DELETE FROM message WHERE id=?", id); err != nil {
		fmt.Println("DeleteMsgs fail :", err)
		return err
	}
	return nil

}

//func main(){
//	db := InitMysqlDB()
//	msg := &Msg{Ty:"room",From:"me",Data:"this is a message",Time:time.Now().Unix(),Ext:"ext message"}
//	msg.To = []string{"user1","user2","user3"}
//	db.PushMsg(msg)
//	msgs,_ := db.GetMsgsFromType("user2",0,"room")
//	for _,m:= range msgs{
//		fmt.Println(m)
//	}
//	for _,c := range db.pool{
//		c.Close()
//	}
//
//}
